
export interface StackListener {
    action: () => void;
    thisArg: any;
}

export default class Stack<T> {
    private data: T[];
    private dataCount: number;

    private triggers: StackListener[];

    constructor(listener?: StackListener) {
        this.data = [];
        this.dataCount = 0;
        this.triggers = [];

        !!listener && this.onChange(listener);
    }

    public push(item: T): Stack<T> {
        this.data.push(item);
        this.dataCount++;
        this.changed();
        return this;
    }
    public pop() {
        if (0 < this.dataCount) {
            this.dataCount--;
        }
        this.changed();
        return this.data.pop();
    }
    public hasItem(item: T) {
        return -1 < this.data.indexOf(item);
    }
    public top() {
        return this.data[this.dataCount - 1];
    }
    public clear(): Stack<T> {
        this.data.splice(0, this.dataCount);
        this.dataCount = 0;
        this.changed();
        return this;
    }
    public remove(item: T): Stack<T> {
        const index: number = this.data.indexOf(item);
        if (-1 < index && index < this.dataCount) {
            this.data.splice(index, 1);
            this.dataCount--;
            this.changed();
        }
        return this;
    }
    public length(): number {
        return this.dataCount;
    }
    public destroy() {
        this.data = null;
        this.dataCount = -1;
        this.triggers = null;
    }
    public onChange(listener: StackListener): Stack<T> {
        this.triggers.push(listener);
        return this;
    }
    private changed() {
        this.triggers.forEach(t => t.action.call(t.thisArg));
    }
}